package com.study.get.jsl;

import cn.hutool.bloomfilter.BitMapBloomFilter;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.alibaba.fastjson2.JSONReader.Feature;
import com.alibaba.fastjson2.TypeReference;
import com.google.common.collect.Lists;
import com.study.get.jsl.BeileizhenDemo.TencentDTO.HqKzzDTO;
import com.study.get.jsl.BeileizhenDemo.TencentDTO.TenRespRootDTO;
import com.study.get.jsl.BeileizhenDemo.TencentDTO.TxRKDTO;
import com.study.utils.SysUtils;
import io.netty.channel.ChannelOption;
import io.netty.handler.timeout.ReadTimeoutHandler;
import io.netty.handler.timeout.WriteTimeoutHandler;
import lombok.Data;
import lombok.experimental.Accessors;
import org.junit.jupiter.api.Test;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeansException;
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.netty.http.client.HttpClient;
import reactor.netty.resources.ConnectionProvider;
import reactor.netty.tcp.TcpClient;

import java.math.BigDecimal;
import java.time.Duration;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author zhuzi
 * 2025/1/30 23:17
 * 避雷针
 */
public class BeileizhenDemo {
    /**
     * 避雷针
     */
    @Test
    public void kzzBlz() {

        String urlCjl = "https://proxy.finance.qq.com/cgi/cgi-bin/rank/hs/getBondRankList?board_type=convertible&sort_type=turnover&direct=down&count={}&offset={}&_rndtime={}&buildType=store&check=11&lang=zh_CN";
        String body = TenTool.webClient.get().uri(StrUtil.format(urlCjl, 200, 0, System.currentTimeMillis() / 1000)).header("Host", "proxy.finance.qq.com").header("Accept", "*/*").header("User-Agent", "QQStock/11.22.1 (iPad; iOS 15.7; Scale/2.00)").header("Referer", "http://zixuanguapp.finance.qq.com").retrieve().bodyToMono(String.class)//
                .timeout(Duration.ofSeconds(18)).retry(3).block();

        TenRespRootDTO<HqKzzDTO> tencentBean = JSON.parseObject(body, new TypeReference<TenRespRootDTO<HqKzzDTO>>() {
        }, Feature.SupportAutoType, Feature.SupportSmartMatch);
        List<HqKzzDTO> rankList = tencentBean.getData().getRankList();

        //过滤正股成交量大于9千万的
        List<HqKzzDTO> collect = rankList.stream().filter(ia -> NumberUtil.isLess(ia.getZxj(), new BigDecimal("200")) && NumberUtil.isGreaterOrEqual(ia.getTurnover(), new BigDecimal("9000"))
                //&& NumberUtil.isGreaterOrEqual(ia.getZdf(), new BigDecimal(""))
        ).collect(Collectors.toList());
        String urlFormat = "https://proxy.finance.qq.com/cgi/cgi-bin/stockinfoquery/kline/app/get?added=false&ktype=day&fqtype=&limit=1&toDate=&warrant=false&code={}&stockType=ZQ-KZZ&fund=false&check=11&lang=zh_CN";
        ArrayList<TxRKDTO> txRKDTOS = Lists.newArrayList();
        for (HqKzzDTO hqKzzDTO : collect) {
            String body2 = TenTool.webClient.get().uri(StrUtil.format(urlFormat, hqKzzDTO.getCode())).header("Host", "proxy.finance.qq.com").header("Accept", "*/*").header("User-Agent", "QQStock/11.22.1 (iPad; iOS 15.7; Scale/2.00)").header("Referer", "http://zixuanguapp.finance.qq.com").retrieve().bodyToMono(String.class)//
                    .timeout(Duration.ofSeconds(8)).retry(3).block();
            JSONObject data = JSON.parseObject(body2).getJSONObject("data");
            List<TxRKDTO> nodes = data.getList("nodes", TxRKDTO.class);

            nodes.forEach(ib -> {
                ib.setCode(hqKzzDTO.getCode());
                ib.setName(hqKzzDTO.getName());
                ib.setZdf(hqKzzDTO.getZdf());
            });
            txRKDTOS.addAll(nodes);
        }

        List<TxRKDTO> collect1 = txRKDTOS.stream().filter(ic -> {
            BigDecimal syl = SysUtils.syl(ic.getHigh(), ic.getOpen());
            BigDecimal sylend = SysUtils.syl(ic.getHigh(), ic.getLast());

            return NumberUtil.isGreaterOrEqual(ic.getLast().add(new BigDecimal(1)), ic.getOpen()) && NumberUtil.isGreaterOrEqual(syl, new BigDecimal("1")) && NumberUtil.isGreaterOrEqual(sylend, new BigDecimal("0.9"));
        }).sorted(Comparator.comparing(TxRKDTO::getLast)).collect(Collectors.toList());
        System.out.println(StrUtil.format("转债\t最新价\t差值\t差值\t涨幅"));
        for (TxRKDTO txRKDTO : collect1) {
            System.out.println(txRKDTO.ding());
        }

    }

    public interface TencentDTO {
        /**
         * 日K
         */
        @Data
        @Accessors(chain = true)
        class TxRKDTO {
            private String code;
            private String name;
            private BigDecimal open;
            private BigDecimal last;
            private BigDecimal high;
            private BigDecimal low;
            //// "amount": "2450460714.00", |成交额24.5亿
            private BigDecimal amount;

            /**
             * 可转债涨跌幅|从其他数据计算的
             */
            private BigDecimal zdf;

            /*  "open": "195.500",
                      "last": "190.471",
                      "high": "199.500",
                      "low": "186.086",
                      "volume": "127122000.00",
                      "amount": "2450460714.00",
                      "exchange": "629.58",
                      "exchangeRaw": "629.5800",
                      "date": "2025-01-27",
                      "oi": "0.000",*/
            public String ding() {
                //松原转债223.56|20|2.28 |差17.72
                return StrUtil.format("{}|{}|{}|{}|{}", name, last, SysUtils.syl(high, open), SysUtils.syl(high, last), zdf);
            }
        }

        @Data
        @Accessors(chain = true)
        class TenRespRootDTO<T> {
            private int code;
            private String msg;
            private TenPage<T> data;
        }

        @Data
        @Accessors(chain = true)
        class TenPage<T> {
            private List<T> rankList;
            private int offset;
            private int total;
        }

        /**
         * 腾讯自选股-行情-可转债列表
         * <p>
         */
        @Data
        @Accessors(chain = true)
        class HqKzzDTO {
            /**
             * 可转债代码 sz123244
             */
            private String code;
            /**
             * 到期日
             */
            private LocalDate dqrq;
            /**
             * 到期赎回价
             */
            private BigDecimal dqshj;
            /**
             * 换手率
             */
            private BigDecimal hsl;
            /**
             * 可转债名称
             */
            private String name;
            /**
             * 评级
             */
            private String pj;
            /**
             * 151.99
             */
            private BigDecimal sd;
            /**
             * 5分钟涨速
             */
            private String speed;
            /**
             * 上市日期
             */
            private LocalDate ssrq;

            private String state;
            /**
             * 股票代码(sz sg)
             */
            private String stockCode;
            private String stockName;
            /**
             * 股票正股涨速
             */
            private String stockSpeed;
            /**
             * 正股类型 ZQ-KZZ
             */
            private String stockType;
            /**
             * 正股涨幅
             */
            private BigDecimal stockZdf;
            /**
             * 正股 开盘价
             */
            private BigDecimal stockZtj;
            /**
             * 正股股价
             */
            private BigDecimal stockZxj;
            /**
             * 剩余规模(W)
             */
            private BigDecimal sygm;
            /**
             * 可转债成交额(W)
             */
            private BigDecimal turnover;
            /**
             * 可转债涨跌幅
             */
            private BigDecimal zdf;
            /**
             * 5日涨跌幅
             */
            private BigDecimal zdfD5;
            /**
             * 转股价
             */
            private BigDecimal zgj;

            /**
             * 转股价值
             */
            private BigDecimal zgjz;
            /**
             * 转股溢价率
             */
            private BigDecimal zgyjl;
            /**
             * 最新价
             */
            private BigDecimal zxj;
        }

        @Data
        @Accessors(chain = true)
        class TenHintDTO {
            private String name;
            /**
             * 最新价
             */
            private BigDecimal zxj;

            /**
             * 可转债涨跌幅
             */
            private BigDecimal zdf;

            /**
             * 正股涨幅
             */
            private BigDecimal stockZdf;

            /**
             * 涨跌幅相差
             */
            private BigDecimal subZdf;


            /**
             * 涨跌幅 设置 (可转债涨幅大于1 且差值大于0.5)
             *
             * @param hintDTO
             * @return
             */
            static boolean predicate(TenHintDTO hintDTO) {
                return Objects.nonNull(hintDTO) &&//
                        NumberUtil.isGreaterOrEqual(hintDTO.getZdf(), new BigDecimal("1")) &&//
                        NumberUtil.isGreaterOrEqual(hintDTO.getSubZdf(), new BigDecimal("1.5"));
            }

            public static TenHintDTO build(HqKzzDTO hqKzzDTO) {
                try {
                    TenHintDTO tenHintDTO = new TenHintDTO();
                    BeanUtils.copyProperties(hqKzzDTO, tenHintDTO);
                    tenHintDTO.setSubZdf(NumberUtil.sub(tenHintDTO.getZdf(), tenHintDTO.getStockZdf()));
                    return tenHintDTO;
                } catch (BeansException e) {
                }
                return null;
            }


            public String ding() {
                //松原转债223.56|20|2.28 |差17.72
                return StrUtil.format("{}|{}|{}|{}|差{}", name, zxj, zdf, stockZdf, subZdf);
            }
        }
    }

    public static class TenTool {
        /**
         * 节假日
         **/
        public static String holidayUrl = "https://timor.tech/api/holiday/year/{}?type=Y&week=Y";

        public static BitMapBloomFilter bloomFilter = new BitMapBloomFilter(10);
        public static WebClient webClient = null;

        static {
            ConnectionProvider provider = ConnectionProvider.builder("fixed").maxConnections(200) // 最大连接数
                    .maxIdleTime(Duration.ofSeconds(60)) // 最大空闲时间
                    .maxLifeTime(Duration.ofSeconds(60)) // 最大存活时间
                    .pendingAcquireTimeout(Duration.ofSeconds(60)) // 等待获取时间
                    .pendingAcquireMaxCount(1000) // 挂起的获取最大计数
                    .build();

            TcpClient tcpClient = TcpClient.create(provider)//
                    .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 15000) // 连接超时时间
                    .doOnConnected(connection -> {
                        connection.addHandlerLast(new ReadTimeoutHandler(5000, TimeUnit.MILLISECONDS)); // 读取超时
                        connection.addHandlerLast(new WriteTimeoutHandler(5000, TimeUnit.MILLISECONDS)); // 写入超时
                    });

            HttpClient httpClient = HttpClient.from(tcpClient).keepAlive(true) // 启用保持连接
                    .responseTimeout(Duration.ofSeconds(10)); // 响应超时时间
            webClient = WebClient.builder()
                    //修改maxInMemorySize的缓存值，默认是256k。修改为10MB
                    .codecs(item -> item.defaultCodecs().maxInMemorySize(10 * 1024 * 1024)).clientConnector(new ReactorClientHttpConnector(httpClient)).build();
        }
    }
}
